#pragma once

#include <string.h>
#include <vector>
#include <iostream>


#include <BasicUsageEnvironment.hh>
#include <liveMedia.hh>
#include <DigestAuthentication.hh>
#include <H264VideoRTPSource.hh>

#include "videostream_ffmpeg.h"

#define DECODEC_TYPE "H264"


class DummySink: public MediaSink {

public:
	DummySink(UsageEnvironment& env, MediaSubsession& subsession, char const* streamId = NULL);
    void SetFFmpegH264Decode(VSFFH264* ffmpegH264) {m_pFfmpeg = ffmpegH264;}
	Boolean Stop();
	virtual ~DummySink();
private:

  	static void afterGettingFrame(void* clientData, unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime, unsigned durationInMicroseconds) {
  		static_cast<DummySink*>(clientData)->afterGettingFrame(frameSize, numTruncatedBytes, presentationTime, durationInMicroseconds);
  	}
  	void afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime, unsigned durationInMicroseconds);

private:
  // redefined virtual functions:
  	virtual Boolean continuePlaying();

private:
    VSFFH264* m_pFfmpeg;
	bool 	  m_bIsWorking = true;
  	u_int8_t* fReceiveBuffer;
  	MediaSubsession& fSubsession;
  	char* fStreamId;
};

class VSRTSPClient : public RTSPClient {
public:
    VSRTSPClient(UsageEnvironment* env, char const* rtspURL, char const* sUser, char const* sPasswd);
	virtual ~VSRTSPClient(); 
    int open();
	bool close();

    int 						m_nState;
	VSFFH264*                   m_pFfmpegH264;
protected:
	void ContinueAfterSetup(int resultCode, char* resultString);
	void ContinueAfterPlay(int resultCode, char* resultString);
	void ContinueAfterDescribe(int resultCode, char* resultString);
	void ContinueAfterTearDown(int resultCode, char* resultString);
	void SendNextCommand(); 
	static void continueAfterSetup(RTSPClient* rtspClient, int resultCode, char* resultString);
	static void continueAfterPlay(RTSPClient* rtspClient, int resultCode, char* resultString);
	static void continueAfterDescribe(RTSPClient* rtspClient, int resultCode, char* resultString);
	static void continueAfterTearDown(RTSPClient* rtspClient, int resultCode, char* resultString);
	// called only by createNew();

private:
    Authenticator 				m_pAuthenticator;
	MediaSession* 				m_pSession;
	MediaSubsession*         	m_pSubSession;
	DummySink*					m_pDummySink;
	MediaSubsessionIterator* 	m_pSubSessionIter;
};
